/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frssl_daq.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2016/03/11 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern "C"{
#include <daq.h>
#include <daq_api.h>
}

#include "frdaq.h"
#include "frlog.h"

#define DAQ_DEFAULT "pcap"

static const DAQ_Module_t *daq_mod = NULL;
//static void* daq_hand = NULL;
static int i_loaded = 0;
//static int s_error = DAQ_SUCCESS;

/*******************************************************************************
*  FUNC     :  DAQ模块加载
*  ARGS     :  dirs                 (模块路径)
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:DAQ_ERROR
*  NOTE     :
*******************************************************************************/
int DAQ_Load(const char* dirs[])
{
    int i_ret = daq_load_modules(dirs);
    if ( i_ret )
    {
        FRLOG_ERROR("Can't load DAQ modules = %d\n", i_ret);
        return DAQ_ERROR;
    }

    i_loaded = 1;
    return DAQ_SUCCESS;
}

/*******************************************************************************
*  FUNC     :  DAQ模块卸载
*  ARGS     :  
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void DAQ_Unload(void)
{
    daq_unload_modules();
    i_loaded = 0;
    
    return;
}

/*******************************************************************************
*  FUNC     :  DAQ初始化
*  ARGS     :  p_module_name        (sfpacket, pcap, etc.)
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:DAQ_ERROR
*  NOTE     :
*******************************************************************************/
int DAQ_Init(const char *p_module_name)
{
    //const char* type = DAQ_DEFAULT;
    daq_mod = daq_find_module(p_module_name);
    if ( !daq_mod )
    {
        FRLOG_ERROR("Can't find %s DAQ!\n", p_module_name);
        return DAQ_ERROR;
    }

    FRLOG_INFO("%s DAQ configured.\n", p_module_name);

//#if HAVE_DAQ_HUP_APPLY
//    if (ControlSocketRegisterHandler(CS_TYPE_HUP_DAQ, &DAQ_PreControl, &DAQ_Control, &DAQ_PostControl))
//    {
//        LogMessage("Failed to register the DAQ control handler.\n");
//    }
//#else
//    LogMessage("The DAQ version does not support reload.\n");
//#endif
//    memset(&daq_stats, 0, sizeof(daq_stats));
    
    return DAQ_SUCCESS;
}

/*******************************************************************************
*  FUNC     :  DAQ配置
*  ARGS     :  cfg              (DAQ_Config_t*)
*           :  p_errbuf         (出错信息保存内存地址)
*           :  ui_buf_size      (出错信息保存内存大小)
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:失败
*  NOTE     :
*******************************************************************************/
static void* __DAQ_Config(DAQ_Config_t* cfg, char *p_errbuf, unsigned int ui_buf_size)
{
    int i_ret;
    char arr_buf[256] = "";
    const char* type = daq_get_name(daq_mod);
    void* daq_hand = NULL;

    if(p_errbuf == NULL)
    {
        p_errbuf = arr_buf;
        ui_buf_size = sizeof(arr_buf);
    }
    
    i_ret = daq_initialize(daq_mod, cfg, &daq_hand, p_errbuf, ui_buf_size);
    if ( i_ret )
    {
        FRLOG_ERROR("Can't initialize DAQ %s (%d) - %s\n", type, i_ret, p_errbuf);
        return NULL;
    }

    return daq_hand;
}

int DAQ_UnprivilegedStart (void* daq_hand)
{
    return ( daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_UNPRIV_START );
}

/*******************************************************************************
*  FUNC     :  DAQ初始化
*  ARGS     :  en_mode          (抓包:DAQ_MODE_PASSIVE; 文件读取:DAQ_MODE_READ_FILE)
*           :  p_input          (DAQ_MODE_PASSIVE时,设备名; 其他 pcap文件名)
*           :  ui_ring_size     (ring buff 大小)
*           :  ui_snaplen       (数据包最大长度)
*           :  ui_timeout       (超时时间 sec)
*           :  p_errbuf         (出错信息保存内存地址)
*           :  ui_buf_size      (出错信息保存内存大小)
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:失败
*  NOTE     :
*******************************************************************************/
void* DAQ_New(DAQ_Mode en_mode
          , char *p_input
          , unsigned int ui_ring_size
          , unsigned int ui_snaplen
          , unsigned int ui_timeout
          , char *p_errbuf, unsigned int ui_buf_size
          , int  *p_i_daq_dlt)
{
    DAQ_Config_t cfg;
    int i_ret=DAQ_ERROR;
    void* daq_hand = NULL;

    if(daq_mod == NULL)
        return NULL;

    memset(&cfg, 0, sizeof(cfg));
    cfg.name = p_input;
    cfg.snaplen = ui_snaplen;
    cfg.timeout = ui_timeout;
    cfg.extra = NULL;
    cfg.flags = 0;
    
    //文件读取
    if( en_mode ==DAQ_MODE_READ_FILE )
    {
        cfg.mode = DAQ_MODE_READ_FILE;
    }
    else //数据抓包
    {
        cfg.mode = DAQ_MODE_PASSIVE;
        cfg.flags |= DAQ_CFG_PROMISC;
        
        //设置buff size
        if(ui_ring_size > 0 && daq_mod != NULL && daq_mod->name != NULL )
        {
            char arr_ring_size[56];
            if( strcmp(daq_mod->name, DAQ_MODULE_PCAP) == 0)
            {
                snprintf(arr_ring_size, sizeof(arr_ring_size), "%u", ui_ring_size * 1024 * 1024);
                daq_config_set_value(&cfg, "buffer_size", arr_ring_size);
                FRLOG_INFO("ui_ring_size=%uM buffer_size=%s", ui_ring_size, arr_ring_size);
            }
            else if( strcmp(daq_mod->name, DAQ_MODULE_AFPACKET) == 0 )
            {
                snprintf(arr_ring_size, sizeof(arr_ring_size), "%u", ui_ring_size);
                daq_config_set_value(&cfg, "buffer_size_mb", arr_ring_size);
                FRLOG_INFO("ui_ring_size=%uM buffer_size_mb=%s", ui_ring_size, arr_ring_size);
            }
        }
    }
    
    daq_hand = __DAQ_Config(&cfg, p_errbuf, ui_buf_size);
    if(daq_hand == NULL)
        return NULL;
    
    //if ( !DAQ_ValidateInstance() )
    //{
    //    snprintf(p_errbuf, ui_buf_size,"DAQ configuration incompatible with intended operation.");
    //    return DAQ_ERROR;
    //}

    if ( DAQ_UnprivilegedStart(daq_hand) )
        *p_i_daq_dlt = daq_get_datalink_type(daq_mod, daq_hand);

    //DAQ_SetFilter(sc->bpf_filter);
    daq_config_clear_values(&cfg);

    return daq_hand;
}

/*******************************************************************************
*  FUNC     :  DAQ 过滤
*  ARGS     :  bpf              (过滤字符串 eg. "host 172.16.0.1")
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:失败
*  NOTE     :
*******************************************************************************/
int DAQ_SetFilter(void* daq_hand, const char* bpf)
{
    int i_ret = 0;

    if ( bpf )
        i_ret = daq_set_filter(daq_mod, daq_hand, bpf);

    if ( i_ret )
        FRLOG_INFO("Can't set DAQ BPF filter to '%s' (%s)!\n",
            bpf, daq_get_error(daq_mod, daq_hand));

    return i_ret;
}

int DAQ_Start(void* daq_hand, char *p_errbuf, unsigned int ui_buf_size, int *p_i_daq_dlt)
{
    int i_ret = daq_start(daq_mod, daq_hand);

    if ( i_ret )
        snprintf(p_errbuf, ui_buf_size, "Can't start DAQ (%d) - %s!", i_ret, daq_get_error(daq_mod, daq_hand));
    else if ( !DAQ_UnprivilegedStart(daq_hand) )
        *p_i_daq_dlt = daq_get_datalink_type(daq_mod, daq_hand);

    return i_ret;
}

int DAQ_Stop (void* daq_hand)
{
    int i_ret = daq_stop(daq_mod, daq_hand);
    if ( i_ret )
        FRLOG_ERROR("Can't stop DAQ (%d) - %s!\n", i_ret, daq_get_error(daq_mod, daq_hand));

    return i_ret;
}

/*******************************************************************************
*  FUNC     :  DAQ 数据获取
*  ARGS     :  max              (max 最大次数)
*           :  callback         (回调函数 DAQ_Analysis_Func_t)
*           :  user             (user_data)
*  RTN      :  成功:DAQ_SUCCESS(0), 其他:失败
*  NOTE     :
*******************************************************************************/
int DAQ_Acquire (void* daq_hand, int max, DAQ_Analysis_Func_t callback, void* user)
{
    int i_ret = daq_acquire(daq_mod, daq_hand, max, callback, user);
    if ( i_ret && i_ret != DAQ_READFILE_EOF )
        FRLOG_ERROR("Can't acquire (%d) - %s!\n", i_ret, daq_get_error(daq_mod, daq_hand));

//    if ( s_error != DAQ_SUCCESS )
//    {
//        i_ret = s_error;
//        s_error = DAQ_SUCCESS;
//    }
    return i_ret;
}

//int DAQ_BreakLoop (void* daq_hand, int error)
//{
//    s_error = error;
//    return ( daq_breakloop(daq_mod, daq_hand) == DAQ_SUCCESS );
//}

//DAQ_Verdict ProcessPacket(Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, void* ft)
//{
//    DAQ_Verdict verdict = DAQ_VERDICT_PASS;
//
//    printf("time:%lu.%lu caplen=%d pktlen=%d\n", pkthdr->ts.tv_sec, pkthdr->ts.tv_usec, pkthdr->caplen, pkthdr->pktlen);
//
//    return verdict;
//}

static DAQ_Verdict PacketCallback(void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
{
    int inject = 0;
    DAQ_Verdict verdict = DAQ_VERDICT_PASS;

    //verdict = ProcessPacket(&s_packet, pkthdr, pkt, NULL);
    printf("time:%lu.%lu caplen=%d pktlen=%d\n", pkthdr->ts.tv_sec, pkthdr->ts.tv_usec, pkthdr->caplen, pkthdr->pktlen);

    return verdict;
}


void PacketLoop (void* daq_hand)
{
    int error = 0;
    int i_loop =0;
    while(i_loop++ <= 100)
        error = DAQ_Acquire(daq_hand, 1, PacketCallback, NULL);
    return;
}


void DAQ_GetError(void* daq_hand, char* p_msg, unsigned int ui_size)
{
    
    if(daq_hand == NULL || p_msg == NULL || ui_size <= 0)
        return;
    
    if(daq_get_error(daq_mod, daq_hand) == NULL)
        return;
        
    snprintf(p_msg, ui_size, "%s", daq_get_error(daq_mod, daq_hand));
    return;
}

//int DAQ_datalink(void)
//{
//    return daq_dlt;
//}

/*******************************************************************************
*  FUNC     :  DAQ 数据包统计
*  ARGS     : 
*  RTN      :  成功:DAQ_Stats_t*, 失败:NULL
*  NOTE     :  不需要释放返回结构体
*******************************************************************************/
DAQ_Stats_t* DAQ_GetStats(void* daq_hand, DAQ_Stats_t *daq_stats)
{
    int i_ret_fun = 0;

    if ( !daq_hand )
        return NULL;

    i_ret_fun = daq_get_stats(daq_mod, daq_hand, daq_stats);
    if ( i_ret_fun )
        FRLOG_ERROR("Can't get DAQ stats (%d) - %s!", i_ret_fun, daq_get_error(daq_mod, daq_hand));

    if ( !daq_stats->hw_packets_received )
        // some DAQs don't provide hw numbers
        // so we default hw rx to the sw equivalent
        // (this means outstanding packets = 0)
        daq_stats->hw_packets_received =
            daq_stats->packets_received + daq_stats->packets_filtered;

    return daq_stats;
}



